package np13.monads;

import np13.Slime;
import np13.Smell;
import np13.World;
import np13.earth.HomeLand;
import np13.ferry.Ferry;
import np13.ferry.Pier;

/**
 * The Homeland monad is responsible for receiving and handling the incoming
 * slimes. This consists of checking for each slime if it belongs to this land.
 * If this is true, the slime is kept on this land. Otherwise, they are sent
 * back to the Funafitu atoll.
 */
public class HomeLandMonad {

	/**
	 * The smell of the homeland, which the monad is responsible for.
	 */
	private final Smell smell;

	/**
	 * The homeland, which the monad is responsible for.
	 */
	private final HomeLand myLand;

	/**
	 * The pier of the land.
	 */

	private final Pier pier;

	/**
	 * True, if the monad is working and false otherwise.
	 */
	private boolean started = false;

	/**
	 * Initializes the monad.
	 * 
	 * @param smell
	 *            The smell of the land, which the monad is responsible for.
	 */
	public HomeLandMonad(Smell smell) {
		this.smell = smell;

		myLand = World.getInstance().getHomeLands().get(smell);
		pier = myLand.getPier();
	}

	/**
	 * Receives and handles the incoming slimes. Slimes belonging to this land
	 * are kept. Otherwise, they are sent back to the Funafitu atoll. Note that
	 * this runs in a daemon-like manner.
	 * 
	 * @throws InterruptedException
	 */
	private void eventLoop() throws InterruptedException {
		Ferry myFerry = pier.getPieredFerry();
		Slime slime;
		while (started) {
			myFerry = pier.getPieredFerry();
			// check if it was a Last Trip
			if (myFerry.getSize() < myFerry.getCapacity())
				started = false;
			// run over all slimes and check if they belong or should be
			// returned to Funafitu
			for (int i = myFerry.getSize(); i > 0; i--) {
				slime = myFerry.popSlime();
				if (myLand.smellsGood(slime))
					myLand.dumpSlime(slime);
				else
					myFerry.pushSlime(slime);
			}
			myFerry.sail();
			// if ending print out home many made it home
			if (!started)
				System.out.println(smell + " recieved " + myLand.campSize());
		}
	}

	/**
	 * @return The smell of the land, which the monad is responsible for.
	 */
	public Smell getSmell() {
		return smell;
	}

	/**
	 * Starts the monad. May be called only once.
	 */
	public synchronized void start() {
		if (started)
			throw new IllegalStateException();
		started = true;

		// create a thread that runs the eventLoop and start it
		System.out.println(Thread.currentThread().getName() + " starting");
		Thread thread = new Thread(new Runnable() {
			@Override
			public void run() {
				try {
					eventLoop();
				} catch (InterruptedException e) {
					e.printStackTrace();
				}
			}
		});
		thread.setName("HomeLand Monad " + smell.name());
		System.out.println(thread.getName() + " starting");

		thread.start();
	}
}
